package dailynewsreader.model;

import java.net.URL;
import java.util.ArrayList;
import java.util.Objects;

/**
 * Ez egy RSS feed
 *
 * @author Zen
 */
public class RSSFeed implements ISearchableFeedEntries {

    /**
     * Az RSS feed címe
     */
    private String title;
    /**
     * Az RSS feed-et tartalmazó oldal linkje
     */
    private String link;
    
    /**
     * Az RSS feed benne van-e kedvencek közt.
     */
    private Boolean isFavourite;
    /**
     * Az RSS feed URL-je
     */
    private URL feedURL;
    /**
     * Ez tárolja a bejegyzéseket
     */
    private ArrayList<RSSEntry> entries;
    /**
     * Stílus beállítások a HTML megjelnítéshez
     */
    private static String styleForHTML = "p { font-size: 12px}"
            + "h2 {margin: 0; padding-top: 20px;}"
            + "span {font-size: 9px; font-style: italic}";
    
    /**
     * RSS feed logó
     */
    private RSSLogo logo;

    /**
     * Konstruktor
     */
    public RSSFeed() {
        this.entries = new ArrayList<RSSEntry>();
        this.title = LabelStorage.FEED_DEFAULT_TITLE;
    }

    /**
     * Konstruktor a feed URLjével együtt történő létrehozáshoz
     *
     * @param feedURL A bejegyzés URL címe
     */
    public RSSFeed(URL feedURL) {
        this();
        this.feedURL = feedURL;
    }

    /**
     * Lekéri a linket
     *
     * @return A link URL-je
     */
    public String getLink() {
        return link;
    }

    /**
     * Beállítja a linket
     *
     * @param link A link URL-je
     */
    public void setLink(String link) {
        this.link = link;
    }

    /**
     * Lekéri a feed URL-jét
     *
     * @return Az URL
     */
    public URL getFeedURL() {
        return feedURL;
    }

    /**
     * BEállítja a feed URL-jét
     *
     * @param feedURL Az URL
     */
    public void setFeedURL(URL feedURL) {
        this.feedURL = feedURL;
    }
    
    /**
     * Kedvenc-e a feed
     * 
     * @return Igaz, ha kedvenc.
     */
    public Boolean isFavourite(){
        return this.isFavourite;
    }
    
    /**
     * Kedvenccé tétele a feed-nek
     * 
     * @param isFavorite 
     */
    public void setIsFavorite(Boolean isFavorite){
        this.isFavourite = isFavorite;
    }

    /**
     * Lekéri a címet
     *
     * @return A feed címe
     */
    public String getTitle() {
        return title;
    }

    /**
     * Visszaadja a feed címét a megadott karakterhosszig. Hasznos lehet pl. a
     * JTree előállításához ha nagyon hosszú lenne az oldal címe. A második
     * paraméterrel a feldolgozás gyorsítható, pl. a cím mögé lehet vele fűzni
     * 3db pontot.
     *
     * @param charCount Eggyi darab karaktert ad vissza a cím elejétől számítva
     * @param concat Hozzáfűzi a string végéhez a megadott szöveget
     * @return Az előállított cím részlet
     */
    public String getTitleShort(int charCount, String concat) {
        return title.substring(0, charCount) + concat;
    }

    /**
     * Beálítja a címet és az entryknek is
     *
     * @param title A feed címe
     */
    public void setTitle(String title) {
        this.title = title;
        for (RSSEntry entry : this.getEntries()){
            entry.setFeedTitle(title);
        }
    }
    
    /**
     * Nem duplikátum, a Dok2.0 miatt került bele. Hasznos lesz, 
     * hogyha az átnevezéskor még valami mást is meg kell csinálni.
     * 
     * @param title A feed új címe
     */
    public void rename(String title) {
        this.setTitle(title); 
    }
    
    /**
     * RSS logó beállítása
     * 
     * @param logo 
     */
    public void setLogo(RSSLogo logo) {
        this.logo = logo;
    }
    
    /**
     * RSS logó lekérdezése
     * 
     * @return Logó objektum
     */
    public RSSLogo getLogo(){
        return this.logo;
    }
    
    /**
     * Lekérdezzük, hogy van-e logója a feed-nek
     * 
     * @return Igaz, ha van logója
     */
    public boolean hasLogo(){
        return (this.logo != null);
    }

    /**
     * Visszaadja az RSS bejegzéseket
     *
     * @return A feed tartalma
     */
    public ArrayList<RSSEntry> getEntries() {
        return entries;
    }

    /**
     * Visszaadja, hogy hány darab elemet tartalmaz a csatorna
     *
     * @return Az összes elem darabszáma
     */
    public int getEntryCount() {
        return this.entries.size();
    }

    /**
     * Visszaadja, hogy hány darab OLVASATLAN elemet tartalmaz a csatorna
     *
     * @return Az összes elem darabszáma
     */
    public int getUnreadEntryCount() {
        int count = 0;

        for (RSSEntry entry : this.entries) {
            if (!entry.isIsRead()) {
                ++count;
            }
        }

        return count;
    }

    /**
     * Hozzáad egy bejegzést a feed-hez
     *
     * @param entry Az RSS bejegyzés, amit hozzá akarunk adni
     */
    public void addEntry(RSSEntry entry) {
        this.entries.add(entry);
    }

    /**
     * Visszaadja, hogy a feed tartalmazza-e a megadott bejegyzést
     *
     * @param entry A vzsgálandó bejegyzés
     * @return Igaz vagy Hamis
     */
    public boolean hasThisEntry(RSSEntry entry) {
        return this.entries.contains(entry);
    }

    /**
     * Kitörli a csatornában található bejegyzéseket
     */
    public void eraseEntries() {
        this.entries = new ArrayList<RSSEntry>();
    }

    /**
     * Kitörli a már olvasott elemeket
     */
    public void eraseUnreadEntries() {
        ArrayList<RSSEntry> toRemove = new ArrayList<RSSEntry>();
        for (RSSEntry entry : this.entries) {
            if (entry.isIsRead()) {
                toRemove.add(entry);
            }
        }
        for (RSSEntry entry : toRemove) {
            this.entries.remove(entry);
        }
    }

    /**
     * Olvasottnak jelöl egy bejegyzést a csatornában
     *
     * @param entryToMark Abejegyzés, amit szeretnénk megjelölni olvasottként
     */
    public void markAsRead(RSSEntry entryToMark) {
        for (RSSEntry entry : this.entries) {
            if (entry.equals(entryToMark)) {
                entry.setIsRead(true);
                break;
            }
        }
    }

    /**
     * A feed összes elemét olvasottnak jelöli
     */
    public void markAllAsRead() {
        for (RSSEntry entry : this.entries) {
            entry.setIsRead(true);
        }
    }

    /**
     * Összehasonlít két feed-et, hogy egyenlőek-e
     *
     * @param obj A csatorna, amivel vizsgáljuk
     * @return Igaz vagy Hamis
     */
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof RSSFeed) {
            if (obj.hashCode() == this.hashCode()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Az RSS URL alapján legenerálja a hash kódját a feed-nek, ami alapján
     * össze lehet hasonlítani egy másikkal
     *
     * @return A generált hash
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + Objects.hashCode(this.feedURL);
        return hash;
    }

    /**
     * Az RSS feed-et alakítja szöveggé
     *
     * @return Az RSS feed szöveges reprezentációja
     */
    @Override
    public String toString() {        
        return this.title;
    }
    
    /**
     * Refactoring: Valószínű már nem kell a konzolra iratás.
     * @return 
     */
    public String toConsoleString(){
     StringBuilder sb = new StringBuilder();

        sb.append("Feed details:\n");
        sb.append("----------------------\n");
        sb.append("Title: " + this.title + "\n");
        sb.append("Link: " + this.link + "\n");
        sb.append("Feed URL: " + this.feedURL + "\n");
        sb.append("\n");

        for (RSSEntry entry : this.entries) {
            sb.append(entry.toString());
            sb.append("\n");
        }

        return sb.toString();
    }

    /**
     * Az RSS feed bejegyzéseket külön bekezdésekbe rakja és HTML tagek közé
     * csomagolja a tartalmat.
     *
     * @return Az RSS feed bejegyzések HTML bekezdésekben
     */
    public String toHTML() {
        StringBuilder sb = new StringBuilder();
        sb.append("<style>");
        sb.append(styleForHTML);
        sb.append("</style>");

        for (RSSEntry entry : this.entries) {
            sb.append("<h2>" + entry.getTitle() + "</h2>");
            sb.append("<a href=\"" + entry.getLink() + "\">");
            sb.append(entry.getLink() + "</a>");
            sb.append("<p>" + entry.getDescription());
            sb.append("<br/><span>" + entry.getAuthor());
            sb.append(", " + entry.getPubDate() + "</span></p>");
            sb.append("<hr>");
        }
        return sb.toString();
    }    

    /**
     * Lekérdező függvény
     * 
     * @param characters A keresési kulcsszó
     * @return A megfelelő bejegyzések tömbje
     */
    @Override
    public ArrayList<RSSEntry> getEntriesFor(String characters) {
        ArrayList<RSSEntry> matches = new ArrayList<RSSEntry>();
        for (RSSEntry entry : this.entries) {
            if (entry.getTitle().contains(characters)) {
                matches.add(entry);
            }
            else if (entry.getDescription().contains(characters)) { //csak akkor nézi meg a szöveget, ha a címben nincs (hatékonyabb)
                matches.add(entry);
            }
        }
        return matches;
    }

}
